/*
 * Copyright (c) 2021 iComm-semi Ltd.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Common defines and declarations for host driver and firmware for all
 * platforms.
 */


#ifndef __FMAC_TX_H__
#define __FMAC_TX_H__


/*******************************************************************************
 *         Include Files
 ******************************************************************************/
#include <linux/version.h>
#include <linux/types.h>
#include <net/cfg80211.h>
#include <linux/ieee80211.h>
#include <linux/netdevice.h>

#include "lmac_types.h"
#include "lmac_msg.h"
#include "ipc_shared.h"
#include "fmac_defs.h"
#include "hal_desc.h"


/*******************************************************************************
 *         Defines
 ******************************************************************************/
#define NX_NB_TID_PER_STA 8
#define NX_NB_TXQ_PER_STA (NX_NB_TID_PER_STA + 1)

#define SSV_HWQ_BK                      (0)
#define SSV_HWQ_BE                      (1)
#define SSV_HWQ_VI                      (2)
#define SSV_HWQ_VO                      (3)
#define SSV_HWQ_BCMC                    (4)
#define SSV_HWQ_NB                      (NX_TXQ_CNT)
#define SSV_HWQ_ALL_ACS                 (SSV_HWQ_BK | SSV_HWQ_BE | SSV_HWQ_VI | SSV_HWQ_VO)
#define SSV_HWQ_ALL_ACS_BIT             (BIT(SSV_HWQ_BK) | BIT(SSV_HWQ_BE) | \
                                        BIT(SSV_HWQ_VI) | BIT(SSV_HWQ_VO) )

#define SSV_TX_LIFETIME_MS              (0x200)
#define SSV_SWTXHDR_ALIGN_SZ            (4)
#define SSV_SWTXHDR_ALIGN_MSK           (SSV_SWTXHDR_ALIGN_SZ - 1)
#define SSV_SWTXHDR_ALIGN_PADS(x) \
                                        ((SSV_SWTXHDR_ALIGN_SZ - ((x) & SSV_SWTXHDR_ALIGN_MSK)) \
                                            & SSV_SWTXHDR_ALIGN_MSK)
#if SSV_SWTXHDR_ALIGN_SZ & SSV_SWTXHDR_ALIGN_MSK
#error bad SSV_SWTXHDR_ALIGN_SZ
#endif

#define AMSDU_PADDING(x)                ((4 - ((x) & 0x3)) & 0x3)

#define TXU_CNTRL_RETRY                 BIT(0)
#define TXU_CNTRL_MORE_DATA             BIT(2)
#define TXU_CNTRL_MGMT                  BIT(3)
#define TXU_CNTRL_MGMT_NO_CCK           BIT(4)
#define TXU_CNTRL_AMSDU                 BIT(6)
#define TXU_CNTRL_MGMT_ROBUST           BIT(7)
#define TXU_CNTRL_USE_4ADDR             BIT(8)
#define TXU_CNTRL_EOSP                  BIT(9)
#define TXU_CNTRL_MESH_FWD              BIT(10)
#define TXU_CNTRL_TDLS                  BIT(11)

#define MAX_AGG_NUM                     (8)
#define MAX_MSDU_SIZE                   (1600)
#define MIN_MSDU_SIZE                   (32)

#define AGG_SUB_HEADER_SIZE             (8)
#define AGG_TAILER_SIZE                 (4)

#if 1
#define RESERVED_TX_SIZE                (0) //(512 - sizeof(struct sdio_hdr) - sizeof(struct txdesc_api))
#else
#define RESERVED_TX_SIZE                (512 - sizeof(struct sdio_hdr) - sizeof(struct txdesc_api))
#endif

#define TX_OFFSET_ALIGN                 (0)



/*******************************************************************************
 *         Enumerations
 ******************************************************************************/


/*******************************************************************************
 *         Structures
 ******************************************************************************/
struct agg_sub_header
{
    u32 jump_len0 : 16,
        jump_len1 : 16;
    u32 extra_info;
};

struct agg_tailer
{
    u32 jump_len0 : 16,
        jump_len1 : 16;
};

struct ssv_mgmt_tx_params {
    struct ieee80211_channel *chan;
    bool offchan;
    unsigned int wait;
    const u8 *buf;
    size_t len;
    bool no_cck;
    bool dont_wait_for_ack;
    int n_csa_offsets;
    const u16 *csa_offsets;
};

struct tx_bmu_desc
{
    u32 mpudu_len;
    u32 upatterntx;             // 0xCAFEFADE
    u32 nextdesc_ptr;
    u32 datastart_ptr;
    u32 dataend_ptr;
    u32 bufctrlinfo;            // FW info field       

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    u32 pageid           : 8,   // [7..0]    current page id
        packetid         : 8,   // [15..8]   sequential packet number generated by HW
        pageseqnum       : 8,   // [23..16]  sequential page number of packet generated by HW
        dw6_reserve_0    : 1,   // [24] 
        lastpageflag     : 1,   // [25]      last page flag, indicate last page of packet
        dw6_reserve_1    : 6;   // [31..26]

#else
    u32 dw6_reserve_1    : 6,   // [31..26]
        lastpageflag     : 1,   // [25]      last page flag, indicate last page of packet
        dw6_reserve_0    : 1,   // [24] 
        pageseqnum       : 8,   // [23..16]  sequential page number of packet generated by HW
        packetid         : 8,   // [15..8]   sequential packet number generated by HW 
        pageid           : 8;   // [7..0]    current page id
#endif
    u32 dw7_reserve;
};

#ifdef CONFIG_MIFI_LOWPOWER
struct probe_resp_info
{
    int data_len;
    uint8_t *data;
};
#endif


/*******************************************************************************
 *         Variables
 ******************************************************************************/
extern const int ssv_tid2hwq[IEEE80211_NUM_TIDS];


/*******************************************************************************
 *         Functions
 ******************************************************************************/
u16 ssv_select_queue(struct net_device *dev, struct sk_buff *skb
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
	, struct net_device *sb_dev
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) 	
	, void *accel_priv
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
	, select_queue_fallback_t fallback
#endif
);
void ssv_tx_flow_control(struct ssv_softc *sc, bool fc_en);
int ssv_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ssv_requeue_multicast_skb(struct sk_buff *skb, struct ssv_vif *ssv_vif);
void ssv_probe_client(struct ssv_softc *sc);
#ifdef SEND_KEEP_ALIVE
void ssv_send_keep_alive(struct ssv_softc *sc);
#endif
int ssv_start_mgmt_xmit(struct ssv_vif *vif, struct ssv_sta *sta,
                         struct ssv_mgmt_tx_params *params, bool offchan,
                         u64 *cookie);

void ssv_set_traffic_status(struct ssv_softc *sc,
                             struct ssv_sta *sta,
                             bool available,
                             u8 ps_id);
void ssv_ps_bh_enable(struct ssv_softc *sc, struct ssv_sta *sta,
                       bool enable);
void ssv_ps_bh_traffic_req(struct ssv_softc *sc, struct ssv_sta *sta,
                            u16 pkt_req, u8 ps_id);

void ssv_downgrade_ac(struct ssv_sta *sta, struct sk_buff *skb);

void ssv_build_tx_bmu_header(struct tx_bmu_desc *tx_bmu_hdr, int tx_len);
int ssv_tx_check_resource(void *app_param, struct sk_buff_head *qhead,
                        int reserved_page, int *p_max_count);
#endif /* __FMAC_TX_H__ */
